﻿using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace SHomeWorkshop.LunarPresentation.Adorners
{
    /// <summary>
    /// 文本块的遮罩。
    /// </summary>
    public class MaskAdorner : Adorner
    {
        /// <summary>
        /// 文本块的罩子。如果其它公式也支持的话，一来并无多大意义，
        /// 二来出现多层遮罩可能看不清。
        /// </summary>
        /// <param name="adornedElement">应传入文本块。</param>
        public MaskAdorner(Expressions.BaseText adornedElement)
            : base(adornedElement)
        {
            //终于解决了选取装饰器中线条宽度为2而不是1像素的问题！！！
            //this.SnapsToDevicePixels = true;
            //this.SetValue(TextOptions.TextFormattingModeProperty, TextFormattingMode.Display);

            this.masterBt = adornedElement;

            this.Cursor = Cursors.Hand;

            this.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(MaskAdorner_PreviewMouseLeftButtonDown);
            this.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(MaskAdorner_PreviewMouseLeftButtonUp);
            this.PreviewMouseRightButtonDown += new MouseButtonEventHandler(MaskAdorner_PreviewMouseRightButtonDown);
        }

        void MaskAdorner_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //完成拖动。
            Globals.DropExpression(this.masterBt);
        }

        void MaskAdorner_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (this.masterBt != null && this.masterBt.Editor != null)
            {
                this.masterBt.Editor.SelectedExpression = this.masterBt;
            }

            e.Handled = true;
        }

        void MaskAdorner_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (this.masterBt != null && this.masterBt.Editor != null)
            {
                this.masterBt.Editor.SelectedExpression = this.masterBt;

                if (Globals.dragSourceExpression != masterBt)
                {
                    Globals.dragSourceExpression = masterBt;
                }
            }

            //e.Handled = true;//会屏蔽格式刷功能。
        }

        private Expressions.BaseText masterBt;

        /// <summary>
        /// 使用本遮罩的公式。应该是个文本块。
        /// </summary>
        public Expressions.BaseText MasterBt
        {
            get { return masterBt; }
            set { masterBt = value; }
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            if (MasterBt == null) return;

            TextFormattingMode tfm = (TextFormattingMode)this.GetValue(TextOptions.TextFormattingModeProperty);
            if (tfm == TextFormattingMode.Display)
            {
                this.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
            }
            else
            {
                this.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Unspecified);
            }

            Rect rect = new Rect(this.AdornedElement.RenderSize);

            Brush renderBrush = masterBt.ExForeground;
            Pen renderPen = new Pen(renderBrush, 1);

            switch (masterBt.Mask)
            {

                case Expressions.BaseText.MaskType.LeftBias:
                    {
                        DrawLeftBias(drawingContext, rect, renderPen);
                        drawingContext.DrawRectangle(Brushes.Transparent, transparentPen, rect);
                        break;
                    }
                case Expressions.BaseText.MaskType.RightBias:
                    {
                        DrawRightBias(drawingContext, rect, renderPen);
                        drawingContext.DrawRectangle(Brushes.Transparent, transparentPen, rect);
                        break;
                    }
                case Expressions.BaseText.MaskType.HLine:
                    {
                        DrawHLine(drawingContext, rect, renderPen);
                        drawingContext.DrawRectangle(Brushes.Transparent, transparentPen, rect);
                        break;
                    }
                case Expressions.BaseText.MaskType.VLine:
                    {
                        DrawVLine(drawingContext, rect, renderPen);
                        drawingContext.DrawRectangle(Brushes.Transparent, transparentPen, rect);
                        break;
                    }
                case Expressions.BaseText.MaskType.HVLine:
                    {
                        DrawHLine(drawingContext, rect, renderPen);
                        DrawVLine(drawingContext, rect, renderPen);
                        drawingContext.DrawRectangle(Brushes.Transparent, transparentPen, rect);
                        break;
                    }
                case Expressions.BaseText.MaskType.None:
                    {
                        return;
                    }
            }
        }

        static MaskAdorner()
        {
            transparentPen = new Pen(Brushes.Transparent, 1);
        }

        private static Pen transparentPen;

        private static Rect DrawRightBias(DrawingContext drawingContext, Rect rect, Pen renderPen)
        {
            double tx, bx;
            bx = 4;

            while (bx < rect.Width + rect.Height)
            {
                tx = bx - rect.Height;

                Point startPt;
                if (tx < rect.Left)
                {
                    startPt = new Point(rect.Left, rect.Top + rect.Left - tx);
                }
                else if (tx < rect.Right && tx >= rect.Left)
                {
                    startPt = new Point(tx, rect.Top);
                }
                else
                {
                    continue;
                }

                Point endPt;
                if (bx < rect.Right)
                {
                    endPt = new Point(bx, rect.Bottom);
                }
                else if (bx >= rect.Right && bx <= rect.Right + rect.Height)
                {
                    endPt = new Point(rect.Right, rect.Bottom - (bx - rect.Right));
                }
                else
                {
                    continue;
                }

                drawingContext.DrawLine(renderPen, startPt, endPt);

                bx += 4;
            }
            return rect;
        }

        private static Rect DrawLeftBias(DrawingContext drawingContext, Rect rect, Pen renderPen)
        {
            double tx, bx;
            tx = 4;

            while (tx < rect.Width + rect.Height)
            {
                bx = tx - rect.Height;

                Point startPt;
                if (tx < rect.Right)
                {
                    startPt = new Point(tx, 0);
                }
                else if (tx < rect.Right + rect.Height)
                {
                    startPt = new Point(rect.Right, rect.Top + tx - rect.Right);
                }
                else
                {
                    continue;
                }

                Point endPt;
                if (bx < rect.Left)
                {
                    endPt = new Point(rect.Left, rect.Bottom - (rect.Left - bx));
                }
                else if (bx >= rect.Left && bx <= rect.Right)
                {
                    endPt = new Point(bx, rect.Bottom);
                }
                else
                {
                    continue;
                }

                drawingContext.DrawLine(renderPen, startPt, endPt);

                tx += 4;
            }
            return rect;
        }

        private static Rect DrawHLine(DrawingContext drawingContext, Rect rect, Pen renderPen)
        {
            double y = rect.Top;

            while (y < rect.Bottom)
            {
                y += 4;
                Point startPt = new Point(rect.Left, y);
                Point endPt = new Point(rect.Right, y);
                drawingContext.DrawLine(renderPen, startPt, endPt);
            }
            return rect;
        }

        private static Rect DrawVLine(DrawingContext drawingContext, Rect rect, Pen renderPen)
        {
            double x = rect.Left;

            while (x < rect.Right)
            {
                x += 4;

                Point startPt = new Point(x, rect.Top);
                Point endPt = new Point(x, rect.Bottom);
                drawingContext.DrawLine(renderPen, startPt, endPt);
            }
            return rect;
        }
    }
}